package com.cy.pj.common.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

/**
 * @Aspect 注解描述的类为Spring容器中的一个切面对象类型(此类型中封装切入点与通知方法)
 * 切入点:要执行的拓展业务的方法的集合
 * 通知方法:封装了在切入点方法上要执行的拓展业务方法
 * @author private
 *
 */
@Aspect//方面,切面
@Slf4j //lombok帮我们生成Log对象
//@Component //将SysLigAspect对象交由Spring进行管理
public class SysLogAspectTest {//Sys系统log模块的切面类
	
	//不使用LomBok需要自动指定如下Log对象
	//private static final Logger log = LoggerFactory.getLogger(SysLogAspect.class);
	
	/**
	 * @Pointcut -->切入点  注解用于描述切入点(在哪些点上执行拓展业务)
	 * bean(bean类的名字) 为一种切入点表达式(这个表达式中定义了哪个或哪些bean对象的方法要进行功能拓展)
	 * 	例如:bean(sysUserServiceImpl)表达式表示名字为sysUserServiceImpl的bean对象中所有方法的集合为切入点
	 * 	也就是说这个sysUserServiceImpl对象中的任意方法执行时都要进行功能扩展
	 */
	@Pointcut("bean(SysUserServiceImpl)")//切入点为静态确定的
	public void doLogPointCut() {} //此方法内部不需要写具体实现,方法名任意
	
	/**
	 * Around注解描述的方法为一个通知方法(服务增益方法),此方法内部可以做服务增益(拓展业务)
	 * 	@Around 注解内部要制动切入点表达式,不要丢掉小括号,在此切入点表达式对应的切入点方法上做功能扩展
	 * @param pj 表示连接点,连接点是动态确定的,用于封装正在执行的切入点方法信息
	 * @return 返回值为目标方法的执行结果
	 * @throws 通知方法执行过程中出现的异常
	 */
	@Around("doLogPointCut()")
	public Object doLogAround(ProceedingJoinPoint pj) throws Throwable {
		long t1 = System.currentTimeMillis();
		log.info("start:{}",t1);
		//执行目标方法
		Object result = pj.proceed();//最终(中间还可以调用本客户其他通知或其他切面的通知)会调用目标方法
		long t2 = System.currentTimeMillis();
		log.info("end:{}",t2);
		String targetClassMethod = getTargetClassMethod(pj);
		log.info("{}目标方法耗时:{}",targetClassMethod,t2-t1);
		System.out.println(result);
		//返回目标方法的执行结果
		return result;
	}

	private String getTargetClassMethod(ProceedingJoinPoint pj) {
		//获取目标对象类型
		Class<?> cls = pj.getTarget().getClass();
		//获取目标对象的类全名
		String targetClassName = cls.getName();
		//获取目标方法名
		MethodSignature signature =(MethodSignature)pj.getSignature();
		String methodName = signature.getName();
		return targetClassName+"."+methodName;
	}
	
}
